#include "cmd.h"

connector *connector_new()
{
	connector *connec = (connector *) malloc(sizeof(connector));
	connec->type = 0;
	connec->next = NULL;
	return connec;
}

void connector_delete(void *connec)
{
	connector *c = (connector *) connec;
	if(c->next != NULL) command_delete(c->next);
	free(c);
}

int is_connector(string *str)
{
	if(str_equals(str, ";"))
		return SIMPLE;
	else if(str_equals(str, "||"))
		return OR;
	else if(str_equals(str, "&&"))
		return AND;
	else if(str_equals(str, "|"))
		return PIPE;
	else if(str_equals(str, "&"))
		return EBG;
	else return 0;
}

int is_redirect_char(string *str)
{
    if(str_equals(str, ">"))
        return SIMPLE_OUT;
    else if(str_equals(str, "<"))
        return SIMPLE_IN;
    else if(str_equals(str, "2>"))
        return SIMPLE_ERR;
    else if(str_equals(str, ">>"))
        return DOUBLE_OUT;
    else if(str_equals(str, "2>>"))
        return DOUBLE_ERR;
    else if(str_equals(str, ">&2"))
        return OUT_ERR;
    else if(str_equals(str, "2>&1"))
        return ERR_OUT;
    else return 0;
}

command *command_new()
{
	command *cmd = (command *)malloc(sizeof(command));
	cmd->args = ll_new();
	cmd->connec = NULL;
	cmd->type = 0;
	cmd->err_fd = STDERR_FILENO;
	cmd->out_fd = STDOUT_FILENO;
	cmd->in_fd = STDIN_FILENO;
	cmd->ground = 0;
	return cmd;
}

void command_delete(void *cmd)
{
	command *c = (command *) cmd;
	ll_delete(c->args, str_delete);
	if(c->connec != NULL) connector_delete(c->connec);
	free(c);
}

int command_is_empty(command *cmd)
{
	return (ll_is_empty(cmd->args));
}

int execute_command(command *cmd)
{
	int ret = 0;
	command *c = cmd;
	int connec_type = 0;

	while(c != NULL)
	{
	    if( connec_type == 0 || connec_type == SIMPLE || connec_type == PIPE || connec_type == EBG ||
	       (connec_type == AND && ret == SUCCESS) || (connec_type == OR && ret == FAILURE) )
	    {

	        redirect_io(c);

            if(c->type == INTERNAL)
            {
                ret = execute_internal_cmd(c);
                if(ret == EXIT) return EXIT;
            }

            else
            {
                ret = execute_external_cmd(c);
                if(ret == NOT_FOUND)
                {
                    fprintf(stdout, "Error: Command ");
                    str_print((string *) ll_get_index(c->args, 0), stdout);
                    fprintf(stdout, " not found!\n");
                    ret = FAILURE;
                }
            }

            unredirect_io(c);
	    }

	    if(c->connec != NULL)
	    {
	        connec_type = c->connec->type;
	        c = c->connec->next;
	    }
	    else c = NULL;
	}

	return SUCCESS;
}

void redirect_io(command *cmd)
{
    int defout, defin, deferr;

    defout = dup(STDOUT_FILENO);
    defin = dup(STDIN_FILENO);
    deferr = dup(STDERR_FILENO);

    if(cmd->in_fd != STDIN_FILENO)
    {
        dup2(cmd->in_fd, STDIN_FILENO);
        close(cmd->in_fd);
    }

    if(cmd->out_fd != STDOUT_FILENO)
    {
        dup2(cmd->out_fd, STDOUT_FILENO);
        close(cmd->out_fd);
    }

    if(cmd->err_fd != STDERR_FILENO)
    {
        dup2(cmd->err_fd, STDERR_FILENO);
        close(cmd->err_fd);
    }

    cmd->in_fd = defin;
    cmd->out_fd = defout;
    cmd->err_fd = deferr;
}

void unredirect_io(command *cmd)
{
    dup2(cmd->in_fd, STDIN_FILENO);
    dup2(cmd->out_fd, STDOUT_FILENO);
    dup2(cmd->err_fd, STDERR_FILENO);
    close(cmd->in_fd);
    close(cmd->out_fd);
    close(cmd->err_fd);
}

char **args_to_argv(command *cmd)
{
	ll_iterator *i = ll_get_iterator(cmd->args);
	char **argv = (char **)malloc( (ll_length(cmd->args) + 1) * sizeof(char *));
	string *s;
	int count = 0;

	argv[ll_length(cmd->args)] = NULL;

	while(!ll_is_end(i))
	{
		s = (string *) ll_get(i);
		argv[count] = str_to_array(s);
		ll_next(i);
		count++;
	}

	return argv;
}
